package com.erlinyou.im.web.config.redis;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * description:
 * 使用spring-data-redis
 * 连接池为lettuce
 * 包括lettuce连接池的配置以及Redistemplate和StringRedistemplate
 *
 */
@Configuration
public class RedisConfiguration {

    @Value("${redis.hostName}")
    private String hostName;
    @Value("${redis.port}")
    private int port;
    @Value("${redis.password}")
    private String password;
    @Value("${redis.maxTotal}")
    private int maxTotal;
    @Value("${redis.maxIdle}")
    private int maxIdle;
    @Value("${redis.minIdle}")
    private int minIdle;
    @Value("${redis.blockWhenExhausted}")
    private boolean blockWhenExhausted;
    @Value("${redis.maxWaitMillis}")
    private int maxWaitMillis;
    @Value("${redis.testOnBorrow}")
    private boolean testOnBorrow;
    @Value("${redis.testOnReturn}")
    private boolean testOnReturn;
    @Value("${redis.testWhileIdle}")
    private boolean testWhileIdle;
    @Value("${redis.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;
    @Value("${redis.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;
//    @Value("${redis.dbIndex}")
//    private int dbIndex;

    @Bean
    public StringRedisSerializer getStringRedisSerializer(){
        return new StringRedisSerializer();
    }

    /**
     * 配置连接池参数
     *
     * @return GenericObjectPool
     */
    @Bean
    public  GenericObjectPoolConfig<?> getRedisConfig() {
        GenericObjectPoolConfig<?> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMaxTotal(maxTotal);
        genericObjectPoolConfig.setMinIdle(minIdle);
        //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
        genericObjectPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
        genericObjectPoolConfig.setMaxWaitMillis(maxWaitMillis);
        //在borrow一个实例时，是否提前进行alidate操作；如果为true，则得到的实例均是可用的
        genericObjectPoolConfig.setTestOnBorrow(testOnBorrow);
        //调用returnObject方法时，是否进行有效检查
        genericObjectPoolConfig.setTestOnReturn(testOnReturn);
        //在空闲时检查有效性, 默认false
        genericObjectPoolConfig.setTestWhileIdle(testWhileIdle);
        //表示idle object evitor两次扫描之间要sleep的毫秒数；
        genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        //表示一个对象至少停留在idle状态的最短时间，
        //然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义；
        genericObjectPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        
        return genericObjectPoolConfig;
    }

    /**
     * lettuce 连接工厂配置
     *
     */
    @Bean
    public RedisConnectionFactory getLettuceConnectionFactory(GenericObjectPoolConfig<?> poolConfig) {
    	
    	LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).build();
    	
    	LettuceConnectionFactory lettuceConnectionFactory = 
    			new LettuceConnectionFactory(new RedisStandaloneConfiguration(hostName, port), clientConfig);
    	
        return lettuceConnectionFactory;
    }

    @Bean(name = "redisTemplate")
    public <K,V> RedisTemplate<K,V> getRedisTemplate(RedisConnectionFactory factory, StringRedisSerializer stringRedisSerializer) {
        RedisTemplate<K, V> redisTemplate = new RedisTemplate<>();
        //对key采用String的序列化方式--统一
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //事务支持
        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }

    @Bean(name = "stringRedisTemplate")
    public StringRedisTemplate getStringRedisTemplate(RedisConnectionFactory factory, StringRedisSerializer stringRedisSerializer) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        //对key采用String的序列化方式--统一
        stringRedisTemplate.setKeySerializer(stringRedisSerializer);
        //事务支持
        stringRedisTemplate.setEnableTransactionSupport(true);
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }

    /**
     * 缓存管理器 使用redisTemplate操作
     */
    @Bean(name = "cacheManager")
    public RedisCacheManager getRedisCacheManager(RedisConnectionFactory factory){
    	return RedisCacheManager.builder(factory).build();
    }
}
